﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using ProgNetComponentsDx.Language;
using ProgNetComponentsDx.Enums;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Localization;
using DevExpress.Utils.Menu;
using DevExpress.XtraGrid.Columns;

namespace ProgNetComponentsDx.Browsers
{
    public partial class BrowserForm : XtraForm
    {
        private Dictionary<BaseEdit, string> filters = new Dictionary<BaseEdit, string>();
        private DataView DataView = null;
        private bool IsTree = false;
        private List<BaseEdit> AllEdits = new List<BaseEdit>();
        public object EditValue
        {
            get;
            set;
        }
        private List<object> SelectedValues = new List<object>();
        
        public bool MultiSelect
        {
            get;
            set;
        }

        public string DisplayFilter
        {
            get;
            set;
        }

        private bool AllowNew
        {
            get { return btnNew.Visible; }
            set { btnNew.Visible = value; }
        }

        private int numOfE = 0;
        private int numOfC = 0;

        public BrowserForm()
        {
            InitializeComponent();
            gvMain.OptionsBehavior.Editable = false;
            gvMain.OptionsCustomization.AllowFilter = false;
            gvMain.OptionsCustomization.AllowGroup = true;
            gvMain.OptionsMenu.EnableFooterMenu = false;
            gvMain.OptionsMenu.EnableGroupPanelMenu = true;
            gvMain.OptionsSelection.EnableAppearanceFocusedCell = false;
            gvMain.OptionsView.ShowFilterPanelMode = DevExpress.XtraGrid.Views.Base.ShowFilterPanelMode.Never;
            gvMain.OptionsView.ShowGroupPanel = false;
            AppearanceObjectExt.SetReadOnlyAppearance(gvMain.Appearance.Row);
            gvMain.PopupMenuShowing += new PopupMenuShowingEventHandler(gvMain_PopupMenuShowing);
        }

        void gvMain_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
        {
            if (e.MenuType == GridMenuType.Column)
            {
                foreach (DXMenuItem item in e.Menu.Items)
                {
                    if (item.Caption == GridLocalizer.Active.GetLocalizedString(GridStringId.MenuColumnColumnCustomization)
                        || item.Caption == GridLocalizer.Active.GetLocalizedString(GridStringId.MenuColumnRemoveColumn))
                    {
                        item.Visible = false;
                    }
                }
            }
        }

        private Browser _Browser;
        private int maxRows = 0;
        GridColumn col;

        public void InitForm(Browser browser, bool AllowNew, object editValue)
        {
            filters.Clear();
            DataView = new DataView(BrowserCache.GetBrowserData(browser.BrowserId, true));
            DataView.RowFilter = DisplayFilter;
            lblCount.Text = gvMain.RowCount + "\\" + DataView.Count;
            maxRows = DataView.Count;
            _Browser = browser;
            if (_Browser.Caption.IsNullOrEmpty())
            {
                this.Text = ProgNetLanguage.sGetStringDefault(_Browser.Name, _Browser.Name);
            }
            else
            {
                this.Text = _Browser.Caption;
            }
            this.AllowNew = AllowNew;
            this.EditValue = editValue;
            SelectedValues.Clear();
            if (MultiSelect)
            {
                if (editValue != null)
                {
                    if (editValue is Array)
                    {
                        SelectedValues.AddRange((object[])editValue);
                    }
                }
            }
            AllEdits.Clear();

            SearchPanel.Controls.Clear();
            SearchPanel.RowStyles.Clear();
            SearchPanel.ColumnStyles.Clear();
            SearchPanel.RowCount = 0;
            SearchPanel.ColumnCount = 0;
            _Browser = browser;
            IsTree = browser.ChildColumn.IsNotNull();
            if (IsTree)
            {
                MainTree.KeyFieldName = browser.ValueMember;
                MainTree.ParentFieldName = browser.ChildColumn;
                MainTree.DataSource = DataView;
                MainTree.Dock = DockStyle.Fill;
                gcMain.Visible = false;
            }
            else
            {
                gvMain.Columns.Clear();
                foreach (BrowserColumn c in _Browser.Columns)
                {
                    gvMain.Columns.Add(BrowserTools.CreateColumn(c, gvMain, this.browserProvider1));
                }

                gcMain.DataSource = DataView;
                gcMain.Dock = DockStyle.Fill;
                MainTree.Visible = false;
            }
            CountFields();
            AddButtons();
            CreateSearchFields();

            if (MultiSelect)
            {
                if (!IsTree)
                {
                    gvMain.OptionsBehavior.Editable = true;
                    foreach (GridColumn c in gvMain.Columns)
                        c.OptionsColumn.AllowEdit = false;

                    col = new GridColumn();
                    col.FieldName = "MULTISELECT";
                    col.UnboundType = DevExpress.Data.UnboundColumnType.Boolean;
                    col.Caption = "Wybierz";
                    col.OptionsColumn.AllowEdit = true;
                    col.Fixed = FixedStyle.Left;
                    col.OptionsColumn.FixedWidth = true;
                    gvMain.Columns.Add(col);
                }
            }
        }
       
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.TopMost = true;
            this.TopMost = false;
            FocusFirstEdit();
            if (BrowserCache.SaveLayouts)
            {
                layoutProvider1.LayoutName = "Browser_" + this._Browser.Name;

                layoutProvider1.GetSettings(this).FormLayoutSettings.SaveSize = BrowserCache.DefaultBrowserFormLayoutSettings.SaveSize;
                layoutProvider1.GetSettings(this).FormLayoutSettings.SavePosition = BrowserCache.DefaultBrowserFormLayoutSettings.SavePosition;

                layoutProvider1.GetSettings(this).FormLayoutSettings.AllowSavePositionChange = BrowserCache.DefaultBrowserFormLayoutSettings.AllowSavePositionChange;
                layoutProvider1.GetSettings(this).FormLayoutSettings.AllowSaveSizeChange = BrowserCache.DefaultBrowserFormLayoutSettings.AllowSaveSizeChange;

                layoutProvider1.SaveCurrentLayoutAsDefault();
                layoutProvider1.ApplySavedLayout();
            }
            if (MultiSelect)
            {
                col.Visible = true;
                col.VisibleIndex = 0;
            }
            if (BrowserCache.SaveLayouts && layoutProvider1.GetSettings(this).FormLayoutSettings.SavePosition)
                return;
            this.CenterToScreen();
        }
        private void FocusFirstEdit()
        {
            foreach (Control c in SearchPanel.Controls)
            {
                if (c is BaseEdit)
                {
                    c.Select();
                    c.Focus();
                    if (c is TextEdit)
                        ((TextEdit)(c)).SelectAll();
                    break;
                }
            }
        }
        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            btnClear.PerformClick();
            if (!IsTree)
            {
                gvMain.FocusedRowHandle = -1;
                for (int i = 0; i < gvMain.RowCount; i++)
                {
                    DataRow r = gvMain.GetDataRow(i);
                    if (r != null)
                        if (r[_Browser.ValueMember].IsTheSame(EditValue))
                        {
                            gvMain.FocusedRowHandle = i;
                            break;
                        }
                }
            }
        }
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            if (BrowserCache.SaveLayouts)
            {
                layoutProvider1.SaveLayout();
            }
        }

        int minSearchHeight
        {
            get { return Browser.UseFilter ? 40 : 80; }
        }
        private void AddButtons()
        {
            if (Browser.UseFilter)
            {
                btnFind.Visible = false;
                btnClear.Top = btnFind.Top;
            }
        }

        private void CreateSearchFields()
        {
            BaseEdit focus = null;
            if ((numOfE + numOfC) > 0)
            {
                #region count rows and columns
                int aRowCount = 0;
                int aColCount = 1;
                decimal reszta = 0;

                if (numOfE > 0)
                    aColCount = 2;

                if (numOfE >= 4)
                    aColCount = 4;

                if (numOfC > 3)
                {
                    if (numOfE > 0)
                        aColCount = 4;
                    else
                    {
                        if (numOfC > 9)
                            aColCount = 4;
                        else if (numOfC > 6)
                            aColCount = 3;
                        else if (numOfC > 3)
                            aColCount = 2;
                    }
                }

                aRowCount = ((numOfE.AsDecimal() * 2) / aColCount).AsInt();
                reszta = ((numOfE.AsDecimal() * 2) % aColCount);
                if (reszta > 0)
                    aRowCount++;

                if (numOfC > 0)
                {
                    int checkEditsPerRow = aColCount;
                    if (numOfE > 0)
                        checkEditsPerRow--;
                    aRowCount += (numOfC.AsDecimal() / checkEditsPerRow).AsInt();
                    reszta = (numOfC.AsDecimal() % checkEditsPerRow);
                    if (reszta > 0)
                        aRowCount++;
                }

                SearchPanel.RowCount = aRowCount;
                SearchPanel.ColumnCount = aColCount;
                for (int rs = 0; rs < aRowCount; rs++)
                {
                    SearchPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 35));
                }
                for (int cs = 0; cs < aColCount; cs++)
                {
                    SearchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
                    //SearchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
                }
                #endregion

                int row = 0;
                int col = 0;
                int i = 0;
                #region Add text edits
                baseEditFormatProvider1.BeginInit();
                foreach (BrowserColumn column in _Browser.Columns)
                {
                    if (column.IsSearchField)
                    {
                        if (column.ColumnType != BrowserColumnType.CheckEdit)
                        {
                            if (col >= aColCount)
                            {
                                row += 1;
                                col = 0;
                            }

                            BaseEdit Edit = CreateEdit(column);
                            Edit.EditValue = null;
                            LabelControl lbl = CreateLabel(column);
                            Edit.TabIndex = i;
                            i++;
                            if (i == 1)
                            {
                                focus = Edit;
                            }
                            SearchPanel.Controls.Add(lbl, col, row);
                            col++;
                            SearchPanel.Controls.Add(Edit, col, row);
                            col++;
                        }
                    }
                }
                baseEditFormatProvider1.EndInit();
                #endregion
                #region Add Checkboxes
                int startColIndex = 0;
                if (numOfE > 0)
                {
                    row++;
                    startColIndex = 1;
                }
                col = startColIndex;

                foreach (BrowserColumn column in _Browser.Columns)
                {
                    if (column.IsSearchField && column.ColumnType == BrowserColumnType.CheckEdit)
                    {
                        BaseEdit Edit = CreateEdit(column);
                        i++;
                        Edit.TabIndex = i;
                        if (i == 1)
                        {
                            Edit.Focus();
                            Edit.SelectAll();
                        }
                        if (col >= aColCount)
                        {
                            row++;
                            col = startColIndex;
                        }

                        SearchPanel.Controls.Add(Edit, col, row);
                        col++;
                    }
                }
                #endregion

                panelFilter.Height = Math.Max(minSearchHeight, SearchPanel.RowCount * 35);

                this.Height = panelFilter.Height + 300;
                if (this.Height > Screen.PrimaryScreen.WorkingArea.Height)
                    this.Height = Screen.PrimaryScreen.WorkingArea.Height;

                this.Width = SearchPanel.ColumnCount * 120 + panelButtons.Width;

                int wid = 0;
                foreach (BrowserColumn c in _Browser.Columns)
                    if (c.Visible)
                        wid += c.Width;
                if (Width < wid)
                    this.Width = wid;

                if (this.Width > Screen.PrimaryScreen.WorkingArea.Width)
                    this.Width = Screen.PrimaryScreen.WorkingArea.Width;
            }
            else
            {
                panelFilter.Visible = false;
            }
            if (focus != null)
            {
                focus.Select();
                focus.Focus();
                focus.SelectAll();
            }
        }

        private void CountFields()
        {
            numOfE = 0;
            numOfC = 0;

            foreach (BrowserColumn col in _Browser.Columns)
            {
                if (col.IsSearchField)
                {
                    if (col.ColumnType == BrowserColumnType.CheckEdit)
                        numOfC++;
                    else
                        numOfE++;
                }
            }
        }

        private BaseEdit CreateEdit(BrowserColumn col)
        {
            BaseEdit e;
            switch (col.ColumnType)
            {
                case BrowserColumnType.CheckEdit:
                    e = new CheckEdit();
                    e.Name = "Edit" + col.Name;
                    ((CheckEdit)(e)).Properties.Appearance.TextOptions.WordWrap = DevExpress.Utils.WordWrap.Wrap;
                    BrowserTools.PrepareProperties(((CheckEdit)(e)).Properties, col);
                    string caption = col.Caption;
                    if (caption.IsNull())
                        e.Text = ProgNetLanguage.sGetStringDefault(col.Name, col.Name);
                    else
                        e.Text = caption;
                    break;
                case BrowserColumnType.DateEdit:
                case BrowserColumnType.DateTimeEdit:
                    e = new DateEdit();
                    ((DateEdit)e).Properties.Mask.EditMask = "d";
                    if (col.ColumnType == BrowserColumnType.DateTimeEdit)
                        ((DateEdit)e).Properties.Mask.EditMask = "g";
                    ((DateEdit)e).Properties.Mask.UseMaskAsDisplayFormat = true;
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((DateEdit)(e)).Properties, col);
                    break;
                case BrowserColumnType.LookUpEdit:
                    e = new LookUpEdit();
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((LookUpEdit)(e)).Properties, col);
                    if (col.BrowserId.IsNotNull())
                        browserProvider1.GetSettings(e).BrowserId = col.BrowserId;
                    baseEditFormatProvider1.GetSettings(e).ClearOnDelete = true;
                    break;/*
                case FieldType.GridLookUpEdit:
                    e = new GridLookUpEdit();
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((GridLookUpEdit)(e)).Properties, col);
                    if (StringExt.IsNotNull(col.BrowserName))
                        dataSourceProvider1.SetBrowserName(e, col.BrowserName);
                    if (col.Browser != null)
                        dataSourceProvider1.SetBrowser(e, col.Browser);
                    break;*/
                case BrowserColumnType.CalcEdit:
                    e = new CalcEdit();
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((CalcEdit)(e)).Properties, col);
                    break;
                case BrowserColumnType.SpinEdit:
                    e = new SpinEdit();
                    baseEditFormatProvider1.GetSettings(e).ClearOnDelete = true;
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((SpinEdit)(e)).Properties, col);
                    break;
                default:
                    e = new TextEdit();
                    e.Name = "Edit" + col.Name;
                    BrowserTools.PrepareProperties(((TextEdit)(e)).Properties, col);
                    break;
            }
            e.KeyDown += new KeyEventHandler(e_KeyDown);
            e.Tag = col.Name;
            e.Properties.NullText = "";
            e.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
            if (Browser.UseFilter)
                e.EditValueChanging += new DevExpress.XtraEditors.Controls.ChangingEventHandler(e_EditValueChanging);
            AllEdits.Add(e);
            return e;
        }
        private LabelControl CreateLabel(BrowserColumn col)
        {
            LabelControl lbl = null;
            if (col != null && col.ColumnType != BrowserColumnType.CheckEdit)
            {
                lbl = new LabelControl();
                lbl.Appearance.Options.UseTextOptions = true;
                lbl.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
                lbl.Appearance.TextOptions.VAlignment = DevExpress.Utils.VertAlignment.Center;
                lbl.AutoSizeMode = DevExpress.XtraEditors.LabelAutoSizeMode.None;
                lbl.Dock = System.Windows.Forms.DockStyle.Fill;
                lbl.Name = "lbl" + col.Name;
                lbl.Size = new System.Drawing.Size(142, 29);
                lbl.TabIndex = SearchPanel.Controls.Count;
                string caption = col.Caption;
                if (caption.IsNull())
                {
                    lbl.Text = ProgNetLanguage.sGetStringDefault(col.Name, col.Name);
                }
                else
                {
                    lbl.Text = caption;
                }
                if (!lbl.Text.EndsWith(":"))
                    lbl.Text += ":";
            }
            return lbl;
        }

        void e_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (!Browser.UseFilter)
                {
                    btnFind.PerformClick();
                }
                else
                {
                    if (IsTree)
                    {
                        if (MainTree.FocusedNode != null && MainTree.VisibleNodesCount == 1)
                            btnOK.PerformClick();
                    }
                    else
                    {
                        if (gvMain.DataRowCount == 1)
                        {
                            for (int i = 0; i < gvMain.RowCount; i++)
                            {
                                if (gvMain.IsDataRow(i))
                                {
                                    gvMain.FocusedRowHandle = i;
                                    break;
                                }
                            }
                            btnOK.PerformClick();
                        }
                    }
                }
            }
        }

        void e_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
        {
            if (Browser.UseFilter)
            {
                BaseEdit ed = sender as BaseEdit;
                if (ed != null)
                {
                    if (filters.ContainsKey(ed))
                        filters[ed] = GetFiletr(ed, e.NewValue);
                    else
                        filters.Add(ed, GetFiletr(ed, e.NewValue));
                }
                ApplyFilter();
            }
        }

        private string GetFiletr(BaseEdit e, object val)
        {
            BrowserColumn col = _Browser.Columns[e.Tag.AsString()];
            string filter = "";
            if (val.IsNotNull())
            {
                if (col != null)
                {
                    switch (col.FilterType)
                    {
                        case FilterType.BeginsWith:
                            filter = col.Name + " LIKE '?%'";
                            break;
                        case FilterType.Bigger:
                            filter = col.Name + " > '?'";
                            break;
                        case FilterType.BiggerOrEqual:
                            filter = col.Name + ">= '?'";
                            break;
                        case FilterType.Contains:
                            filter = col.Name + " LIKE '%?%'";
                            break;
                        case FilterType.EndsWith:
                            filter = col.Name + " LIKE '%?'";
                            break;
                        case FilterType.Equal:
                            filter = col.Name + " = '?'";
                            break;
                        case FilterType.NotEqual:
                            filter = col.Name + " <> '?'";
                            break;
                        case FilterType.Smaller:
                            filter = col.Name + " < '?'";
                            break;
                        case FilterType.SmallerOrEqual:
                            filter = col.Name + "<= '?'";
                            break;
                    }
                    filter = filter.Replace("?", val.AsString().PrepareString());
                }
            }
            return filter;
        }
        private string GetFiletr(BaseEdit e)
        {
            return GetFiletr(e, e.EditValue);
        }

        private void ApplyFilter()
        {
            string filter = DisplayFilter;
            if (Browser.UseFilter)
            {
                foreach (string s in filters.Values)
                {
                    if (s.IsNotNull())
                    {
                        filter = filter.AppendAnd();
                        filter += "(" + s + ")";
                    }
                }
                DataView.RowFilter = filter;
            }
            else
            {
                foreach (BaseEdit e in AllEdits)
                {
                    string s = GetFiletr(e);
                    if (s.IsNotNull())
                    {
                        filter = filter.AppendAnd();
                        filter += "(" + s + ")";
                    }
                }
                DataView.RowFilter = filter;
            }

            if (IsTree)
                MainTree.RefreshDataSource();
            else
                gcMain.RefreshDataSource();
        }

        private void btnFind_Click(object sender, EventArgs e)
        {
            ApplyFilter();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            foreach (BaseEdit ed in AllEdits)
            {
                ed.EditValue = _Browser.Columns[ed.Tag.AsString()].DefaultValue;
            }
            FocusFirstEdit();
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            EditValue = null;
            DialogResult = DialogResult.OK;
            Close();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            EditValue = GetEditValue();
            if (EditValue != null)
            {
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }

        private object GetEditValue()
        {
            if (IsTree)
            {
                if (MainTree.FocusedNode != null)
                    MainTree.FocusedNode.GetValue(_Browser.ValueMember);
            }
            else
            {
                if (MultiSelect)
                {
                    if (SelectedValues.Count > 0)
                    {
                        return SelectedValues.ToArray();
                    }
                }
                else
                {
                    DataRow r = gvMain.GetFocusedDataRow();
                    if (r != null)
                        return r[_Browser.ValueMember];
                }
            }
            return null;
        }

        private void gvMain_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (MultiSelect)
                {
                    bool selected = gvMain.GetRowCellValue(gvMain.FocusedRowHandle, col).AsBool();
                    gvMain.SetRowCellValue(gvMain.FocusedRowHandle, col, !selected);
                }
                else
                {
                    btnOK_Click(btnOK, EventArgs.Empty);
                }
            }
        }

        private void gvMain_RowCountChanged(object sender, EventArgs e)
        {
            lblCount.Text = gvMain.RowCount + "\\" + maxRows;
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Control | Keys.Down))
            {
                bool focused;

                foreach (BaseEdit edit in AllEdits)
                {
                    focused = edit.Focused;
                    if (edit is TextEdit)
                    {
                        focused |= ((TextEdit)edit).MaskBox.Focused;
                    }
                    if (focused)
                    {
                        if (IsTree)
                            this.MainTree.Focus();
                        else
                            this.gcMain.Focus();
                        break;
                    }
                }
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void gvMain_CustomUnboundColumnData(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDataEventArgs e)
        {
            if (e.IsGetData)
            {
                DataRowView rw = e.Row as DataRowView;
                if (rw != null)
                {
                    e.Value = SelectedValues.Contains(rw[_Browser.ValueMember]);
                }
            }
            else if (e.IsSetData)
            {
                DataRowView rw = e.Row as DataRowView;
                if (rw != null)
                {
                    if (e.Value.AsBool())
                    {
                        SelectedValues.Add(rw[_Browser.ValueMember]);
                    }
                    else
                    {
                        SelectedValues.Remove(rw[_Browser.ValueMember]);
                    }
                }
            }
        }

        private void gvMain_DoubleClick(object sender, EventArgs e)
        {
            if (gvMain.GetDataRowUndetCursor() != null)
            {
                if (MultiSelect)
                {
                    bool selected = gvMain.GetRowCellValue(gvMain.FocusedRowHandle, col).AsBool();
                    gvMain.SetRowCellValue(gvMain.FocusedRowHandle, col, !selected);
                }
                else
                {
                    btnOK_Click(btnOK, EventArgs.Empty);
                }
            }
        }
        
    }
}
